import java.io.IOException;
import java.math.BigInteger;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public class Ip {
    private byte[] data;
    private long numbers;
    private Map<Long, Long> prefStart = new HashMap<>();
    private Map<Long, Long> prefEnd = new HashMap<>();

    private static Ip instance = null;

    private Ip(String filePath) throws IOException {
        Path path = Paths.get(filePath);

        try {
            data = Files.readAllBytes(path);
        } catch (IOException e) {
            throw new IOException("file not found" + e);
        }

        numbers = unpackInt4byte(data[4], data[5], data[6], data[7]);

        for (int k = 0; k < numbers; k++) {
            int i = k * 12 + 4 + 4;
            prefStart.put(unpackInt4byte(data[i + 8], data[i + 9], data[i + 10], data[i + 11]), unpackInt4byte(data[i], data[i + 1], data[i + 2], data[i + 3]));
            prefEnd.put(unpackInt4byte(data[i + 8], data[i + 9], data[i + 10], data[i + 11]), unpackInt4byte(data[i + 4], data[i + 5], data[i + 6], data[i + 7]));
        }
    }

    public static synchronized Ip getInstance(String path) throws IOException {
        if (instance == null)
            instance = new Ip(path);
        return instance;
    }

    public String get(String ip) {
        try {
            InetAddress inetAddress = InetAddress.getByName(ip);
            if (!(inetAddress instanceof Inet6Address)) {
                throw new IllegalArgumentException("Not an IPv6 address: " + ip);
            }
            ip = inetAddress.getHostAddress();
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid IPv6 address: " + ip, e);
        }
        if (ip.contains("%")) {
            ip = ip.split("%")[0];
        }
        String[] ips = ip.split("\\:");
        long pref = Long.parseLong(ips[0], 16);
        BigInteger val = stringToBigInt(ip);
        if (prefStart.get(pref) == null || prefEnd.get(pref) == null) {
            return "保留|保留|||||||||||||||||";
        }
        long low = prefStart.get(pref), high = prefEnd.get(pref);
        long cur = low == high ? low : search(low, high, val);
        return getAddr(cur);

    }

    private int search(long low, long high, BigInteger k) {
        int M = 0;
        while (low <= high) {
            int mid = (int) (low + high) / 2;
            int p = (int) numbers * 12 + 4 + 4 + (mid * 55);
            BigInteger endIpNum = new BigInteger(new String(Arrays.copyOfRange(data, p, p + 50)).replaceAll("\\*", ""));
            if (endIpNum.compareTo(k) == 0 || endIpNum.compareTo(k) == 1) {
                M = mid;
                if (mid == 0) {
                    break;
                }
                high = mid - 1;
            } else
                low = mid + 1;
        }
        return M;
    }

    private long unpackInt4byte(byte a, byte b, byte c, byte d) {
        return (a & 0xFFL) | ((b << 8) & 0xFF00L) | ((c << 16) & 0xFF0000L) | ((d << 24) & 0xFF000000L);
    }

    public static BigInteger stringToBigInt(String ipInString) {
        ipInString = ipInString.replace(" ", "");
        byte[] bytes = ipv6ToBytes(ipInString);
        return new BigInteger(bytes);
    }

    public String getAddr(long cur) {
        int j = (int) (numbers * 12 + 4 + 4 + (cur * 55));
        int offset = (int) unpackInt4byte(data[j + 50], data[1 + j + 50], data[2 + j + 50], data[3 + j + 50]);
        int length =  data[50 + j + 4] & 0xff;
        return new String(Arrays.copyOfRange(data, offset, (offset + length)));
    }

    public static byte[] ipv6ToBytes(String ipv6) {
        try {
            // 去除可能的区域索引（如fe80::1%eth0 -> fe80::1）
            String pureIpv6 = ipv6.split("%")[0];
            // 使用InetAddress解析
            InetAddress inetAddress = InetAddress.getByName(pureIpv6);
            if (!(inetAddress instanceof Inet6Address)) {
                throw new IllegalArgumentException("Not an IPv6 address: " + ipv6);
            }
            // 直接返回16字节的地址
            return inetAddress.getAddress();
        } catch (UnknownHostException e) {
            throw new IllegalArgumentException("Invalid IPv6 address: " + ipv6, e);
        }
    }


    public static void main(String[] args) throws IOException {
        Ip ip = Ip.getInstance("file_path");
        System.out.println(ip.get("ip_address"));
    }

}